# This is a sample Python script.
import base64
import json
import logging
import math
import os
import random
import time
import tkinter as tk
import urllib.request
from tkinter import filedialog, messagebox

import requests
from openai import OpenAI

logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(name)s %(levelname)s %(pathname)s %(lineno)s %(funcName)s - %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S')
impage_types = [('图片文件', '.jpg'), ('图片文件', '.png'), ('图片文件', '.jpeg')]


def center_window_auto(window):
    """
    将窗口居中显示，并自动设置窗口宽度。
    """
    window.update_idletasks()  # 更新窗口布局
    width = window.winfo_width()  # 获取窗口宽度
    height = window.winfo_height()  # 获取窗口高度

    # 获取屏幕尺寸
    screen_width = window.winfo_screenwidth()
    screen_height = window.winfo_screenheight()

    # 计算窗口居中的位置
    x = (screen_width - width) // 2
    y = (screen_height - height) // 2

    # 设置窗口位置
    window.geometry(f"{width}x{height}+{x}+{y}")


def center_window(window, width, height):
    """
    将窗口居中显示。
    """
    # 获取屏幕尺寸
    screen_width = window.winfo_screenwidth()
    screen_height = window.winfo_screenheight()

    # 计算窗口居中的位置
    x = (screen_width - width) // 2
    y = (screen_height - height) // 2

    # 设置窗口位置
    window.geometry(f"{width}x{height}+{x}+{y}")


def get_user_input():
    """
    弹出用户输入框和文件选择框，获取用户输入的内容和文件路径。
    """

    def submit():
        nonlocal user_input, file_path, is_submitted
        user_input = entry.get()
        file_path = entry_file.get()
        if user_input:
            logging.info('输入的提示词：{} '.format(user_input))
            is_submitted = True
            root.destroy()  # 关闭窗口
        else:
            messagebox.showwarning("输入不完整", "请输入内容!")
        if file_path:  # 如果用户选择了文件
            stat = os.stat(file_path)
            file_size = stat.st_size / 1024
            logging.info('选择的文件：{} 文件大小：【{}】 kb'.format(file_path, str(file_size)))

    def select_file():
        file_path = filedialog.askopenfilename()
        if file_path:  # 如果用户选择了文件
            entry_file.delete(0, tk.END)  # 清空输入框
            entry_file.insert(0, file_path)  # 插入文件路径
            # stat = os.stat(file_path)
            # file_size = stat.st_size / 1024
            # logging.info('选择的文件：{} 文件大小：【{}】 kb'.format(file_path, str(file_size)))
        # file_label.config(text=file_path)

    def on_closing():
        """
        监听窗口关闭事件。
        """
        nonlocal is_closed_by_user
        is_closed_by_user = True
        root.destroy()

    # 初始化用户输入和文件路径
    user_input = None
    file_path = None
    is_submitted = False  # 是否通过“提交”按钮关闭窗口
    is_closed_by_user = False  # 是否通过关闭按钮关闭窗口

    # 创建 GUI 窗口
    root = tk.Tk()
    root.title("用户输入和文件选择")
    # root.withdraw()
    # 监听窗口关闭事件
    root.protocol("WM_DELETE_WINDOW", on_closing)
    # 创建输入框
    label_text = tk.Label(root, text="请输入内容:")
    label_text.grid(row=0, column=0, padx=5, pady=5, sticky="w")
    # 文本输入框
    entry = tk.Entry(root, width=50)
    entry.grid(row=0, column=1, padx=5, pady=5)
    # entry.pack(pady=5)

    # 创建文件选择按钮
    label_file = tk.Label(root, text="请选择文件:")
    label_file.grid(row=1, column=0, padx=5, pady=5, sticky="w")

    entry_file = tk.Entry(root, width=50)
    entry_file.grid(row=1, column=1, padx=5, pady=5)

    btn_browse = tk.Button(root, text="浏览...", command=select_file)
    btn_browse.grid(row=1, column=2, padx=5, pady=5)

    # 提交按钮
    btn_submit = tk.Button(root, text="提交", command=submit)
    btn_submit.grid(row=2, column=1, pady=10)

    center_window_auto(root)
    # 运行主循环
    root.mainloop()

    # 返回用户输入的内容和文件路径，以及窗口关闭方式
    if is_closed_by_user:
        raise SystemExit('用户直接关闭了弹框，程序结束。')
    elif is_submitted:
        pass
    else:
        raise SystemExit('用户未输入内容或未选择文件，程序结束。')
    return user_input, file_path


# 本地文件转文件URL（openai不支持本地文件URL）
def img_to_url(window_url=r"D:\modelscope\370400\370400+2020-370402-84-03-095801+55609b4d-3141-4504-b63b-3e17a5585a41.jpg"):
    url_path = urllib.request.pathname2url(window_url)
    full_url = "file:" + url_path
    return full_url


# 照片转base64
def image_to_base64(file_path):
    with open(file_path, "rb") as image_file:
        encoded_string = base64.b64encode(image_file.read())
    return encoded_string.decode("utf-8")


# deepseek_api 测试用
def deepseek_api(messages_, url="http://localhost:11434/api/generate", model_name="deepseek-r1:32b"):
    # url = "http://localhost:11434/api/generate"
    # url = 'http://192.168.3.164:11434/v1/completions'
    headers = {"Content-Type": "application/json"}
    data1 = {
        "model": model_name,
        "messages": [
            {"role": "system", "content": "You are a helpful assistant."},
            {"role": "user", "content": "天为什么是蓝色的？"}
        ]
        # "stream": false
    }
    data = {
        "model": model_name,
        "prompt": "Write a Python function that calculates the factorial of a number",
        "num_results": 1,
        "max_tokens": 500,
        "temperature": 0.7,
        "top_p": 1.0,
        "repetition_penalty": 1.0,
        "stop": ["\n"]
    }

    response = requests.post(url, headers=headers, data=json.dumps(data1))
    print(response.json())


# 照片转base64,openai使用
def local_image_to_base64(image_path):
    with open(image_path, "rb") as f:
        encoded_image = base64.b64encode(f.read())
    encoded_image_text = encoded_image.decode("utf-8")
    base64_qwen = f"data:image;base64,{encoded_image_text}"
    return base64_qwen


# openai测试Qwen
def openai_api(messages, openai_api_base="http://localhost:7777/v1", openai_api_key="EMPTY", model_name="/mnt/g/modelscope/Qwen2.5-VL-7B-Instruct-AWQ"):
    client = OpenAI(
        api_key=openai_api_key,
        base_url=openai_api_base,
    )
    response = client.chat.completions.create(
        model=model_name,
        messages=messages,
        stream=False
        , timeout=1000 * 60 * 30
    )
    return response.choices[0].message.content


def add_image_content(messages, file_path):
    if file_path is not None:
        stat = os.stat(file_path)
        file_size = stat.st_size / 1024
        # logging.info('选择的文件：{} 文件大小：【{}】 kb'.format(file_path, str(file_size)))
        base_ = local_image_to_base64(file_path)
        for m in messages:
            role = m.get('role')
            if role == 'user':
                content = m.get('content')
                content.append({"type": "image_url", "image_url": {"url": base_}, })
                m.setdefault("content", content)
    return messages, file_size


if __name__ == '__main__':
    print("程序启动，等待用户输入...")
    # user_input = '123'
    # file_path = 'test-rest.log'
    user_input, file_path = get_user_input()

    messages = [
        # {"role": "system", "content": "You are a helpful assistant."},
        {
            "role": "user",
            "content": [
                {"type": "text", "text": user_input},
            ],
        },
    ]

    if file_path:
        messages, size_kb = add_image_content(messages, file_path)
    start = time.time()
    logging.info('开始时间【{}】'.format(start))
    openai_respose = openai_api(messages)
    # openai_respose = 'asdafdsasdfadfsadfasdfsaasaafsfadfasdfsafdasds'
    time.sleep(random.randint(1, 10))
    logging.info('返回数据：【{}】'.format(openai_respose))
    end = time.time()
    logging.info('结束时间【{}】'.format(end))
    logging.info('总用时【{}】秒'.format((end - start)))
    # 秒
    duration = math.ceil((end - start))

    format_ = '总用时: {} 分'.format(math.ceil((end - start) / 60)) if duration > 60 else '总用时: {} 秒'.format(str(duration))

    with open('test-rest.log', 'a+', encoding='utf-8') as f:
        if file_path:
            f.write('选择的文件: {}，文件大小：{} kb'.format(time.strftime(file_path), str(math.ceil(size_kb))) + '\n')
        f.write('开始时间: {},timestamp: {}'.format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start)), start) + '\n')
        f.write('结束时间: {},timestamp: {}'.format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end)), end) + '\n')
        f.write(format_ + '\n')
        f.write('----------------------返回数据-start:-------------------------------------------' + '\n')
        f.write('{}'.format(openai_respose) + '\n')
        f.write('----------------------返回数据-end:-------------------------------------------' + '\n\n')

'''

messages=[
    # {"role": "system", "content": "You are a helpful assistant"},
    # {"role": "user", "content": "Hello"},

    # {"role": "system", "content": "You are a helpful assistant."},
    # {"role": "user", "content": "天为什么是蓝色的？"}

    {"role": "system", "content": "You are a helpful assistant."},
    {
        "role": "user",
        "content": [
            {
                "type": "image_url",
                "image_url": {
                    "url": "https://modelscope.oss-cn-beijing.aliyuncs.com/resource/qwen.png"
                },
            },
            {"type": "text", "text": "What is the text in the illustrate?"},
        ],
    },
],
'''

# See PyCharm help at https://www.jetbrains.com/help/pycharm/
# 您在调用 DeepSeek API 时，可能会遇到以下错误。这里列出了相关错误的原因及其解决方法。
#
# 错误码	描述
# 400 - 格式错误	原因：请求体格式错误
# 解决方法：请根据错误信息提示修改请求体
# 401 - 认证失败	原因：API key 错误，认证失败
# 解决方法：请检查您的 API key 是否正确，如没有 API key，请先 创建 API key
# 402 - 余额不足	原因：账号余额不足
# 解决方法：请确认账户余额，并前往 充值 页面进行充值
# 422 - 参数错误	原因：请求体参数错误
# 解决方法：请根据错误信息提示修改相关参数
# 429 - 请求速率达到上限	原因：请求速率（TPM 或 RPM）达到上限
# 解决方法：请合理规划您的请求速率。
# 500 - 服务器故障	原因：服务器内部故障
# 解决方法：请等待后重试。若问题一直存在，请联系我们解决
# 503 - 服务器繁忙	原因：服务器负载过高
# 解决方法：请稍后重试您的请求
